#include "StdAfx.h"
#include "Terrain.h"
#include "Level.h"
#include "GraphCamera.h"
#include "PhysX.h"

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

Terrain::Terrain(Level *pLevel, InitInfo& info)
	:LevelElement()
	,m_IntInfo(info)
	,m_NumColumns(info.NumCols)
	,m_NumRows(info.NumRows)
	,m_TileSize(info.CellSpacing)
	,m_ScaleHeight(info.HeightScale)
	,m_Offset(info.HeightOffset)
	,m_pVertexLayout(0)
	,m_pVertexBuffer(0)
	,m_pIndexBuffer(0)
	,m_pDefaultEffect(0)	
	,m_pDefaultTechnique(0)	
	,m_pTextureLow(0)
	,m_pTextureBase(0)
	,m_pTextureMid(0)
	,m_pTextureHigh(0)
	,m_pWorldViewProjectionVariable(NULL)
	,m_pTextureLowVariable(0)
	,m_pTextureBaseVariabele(0)
	,m_pTextureMidVariabele(0)
	,m_pTextureHighVariabele(0)
	,m_pWorldVariable(0)
	,m_pEyePosVariable(0)
	,mfxLightVar(0)
	,m_pHeightOffsetVariable(0)
	,m_SnowLine(0.6f)
	,m_RockLine(0.45f)
	,m_GrassLine(0.04f)
	,m_SandLine(0.05f)
	,m_WaterHeight(-100)
	,m_bReflection(false)
	,m_bClipping(false)
	,m_bShadowmap(false)
{
	m_pLevel = pLevel;
}

Terrain::~Terrain(void)
{
	SafeRelease(m_pVertexBuffer );
	SafeRelease(m_pVertexLayout);
	SafeRelease(m_pIndexBuffer);
}
void Terrain::Initialize(ContentManager *pContentManager)
{
	CreateEffect(pContentManager);

	//Loading the textures
	m_pTextureLow=		pContentManager->GetTexture(m_pLevel->GetDevice(), m_IntInfo.TextureLow);
	m_pTextureBase=		pContentManager->GetTexture(m_pLevel->GetDevice(), m_IntInfo.TextureBase);
	m_pTextureMid=		pContentManager->GetTexture(m_pLevel->GetDevice(), m_IntInfo.TextureMid);
	m_pTextureHigh=		pContentManager->GetTexture(m_pLevel->GetDevice(), m_IntInfo.TextureHigh);
	
	//Loading Heigtmap
	if(LoadHeightMap())
	{
		Smooth();
		CreateVerticesAndTriangles();
		DefineInputlayout();
		BuildVertexBuffer();
		BuildIndexBuffer();
		CreatePhysicsTerrain();
		//Generate blendmap
		GenerateBlendMap();


		//Zoek het hoogste punt
		vector<VertexPosNormTex>::iterator pos;

		float hoogstepunt = m_IntInfo.HeightOffset;
		for(pos = m_VecVertices.begin(); pos != m_VecVertices.end(); ++pos)
		{
			if((*pos).pos.y > hoogstepunt)
				hoogstepunt = (*pos).pos.y;
		}

		m_BoundingBox.push_back(D3DXVECTOR3(m_VecVertices[0].pos.x, m_VecVertices[0].pos.y, m_VecVertices[0].pos.z));
		m_BoundingBox.push_back(D3DXVECTOR3(m_IntInfo.NumRows*m_IntInfo.CellSpacing,0,0)); //rechts ervan
		m_BoundingBox.push_back(D3DXVECTOR3(0,0,m_IntInfo.NumRows*m_IntInfo.CellSpacing)); //voor ervan
		m_BoundingBox.push_back(D3DXVECTOR3(m_IntInfo.NumRows*m_IntInfo.CellSpacing,0,m_IntInfo.NumRows*m_IntInfo.CellSpacing)); //voor rechts ervan
	
		D3DXVECTOR3 p5 =  D3DXVECTOR3(m_VecVertices[0].pos.x, m_VecVertices[0].pos.y, m_VecVertices[0].pos.z); //Top
		p5.y = hoogstepunt;
		m_BoundingBox.push_back(p5);
		m_BoundingBox.push_back(D3DXVECTOR3(m_IntInfo.NumRows*m_IntInfo.CellSpacing,hoogstepunt,0)); //rechts ervan
		m_BoundingBox.push_back(D3DXVECTOR3(0,hoogstepunt,m_IntInfo.NumRows*m_IntInfo.CellSpacing)); //voor ervan
		m_BoundingBox.push_back(D3DXVECTOR3(m_IntInfo.NumRows*m_IntInfo.CellSpacing,hoogstepunt,m_IntInfo.NumRows*m_IntInfo.CellSpacing)); //voor rechts ervan
	}

}
void Terrain::Draw(const RenderContext* pRenderContext)
{
	if(!m_pDefaultTechnique )
	{
		MessageBox(0,_T("No Technique"),_T("ERROR"),0);
		return;
	}
	if(!m_pVertexBuffer)
	{
		MessageBox(0,_T("No Vertices"),_T("ERROR"),0);
		return;
	}	
	
	m_pLightWVPVariable->SetMatrix(m_LightWVPMatrix);

	if(!m_bShadowmap)
		m_pShadowMapVariabele->SetResource(m_ShadowDepthMapTexture);
	// Update Shader matrix variables
	D3DXMATRIX matView;
	if(!m_bReflection)
		matView = pRenderContext->GetCamera()->GetView();
	else
		matView = m_ReflectionViewMatrix;

	if(m_bClipping)
		clipPlanePtr->SetFloatVector((float*)&m_Clippingplane);
	else
		clipPlanePtr->SetFloatVector((float*)&D3DXPLANE(0.0f, 0.0f, 0.0f, 0.0f));
	D3DXMATRIX matProj = pRenderContext->GetCamera()->GetProj();
	m_pWorldViewProjectionVariable->SetMatrix((float*)&(m_World*matView*matProj));

	m_pWorldVariable->SetMatrix((float*)&(m_World));

	D3DXVECTOR3 pos = pRenderContext->GetCamera()->GetPos();
	m_pEyePosVariable->SetRawValue(&pos,0,sizeof(D3DXVECTOR3));

	m_pHeightOffsetVariable->SetFloat(m_ScaleHeight);

	// Set the input layout
    m_pLevel->GetDevice()->IASetInputLayout( m_pVertexLayout );

	//set the texture variabele
	m_pTextureLowVariable->SetResource(m_pTextureLow);	
	m_pTextureBaseVariabele->SetResource(m_pTextureBase);
	m_pTextureMidVariabele->SetResource(m_pTextureMid);
	m_pTextureHighVariabele->SetResource(m_pTextureHigh);
	m_pBlendmapVariabele->SetResource(m_pBlendMap);


	m_pFogModeVariable->SetInt(pRenderContext->GetFogInfo().FogMode);
	m_pFogStartVariable->SetFloat(pRenderContext->GetFogInfo().FogStart);
	m_pFogEndVariable->SetFloat(pRenderContext->GetFogInfo().FogEnd);
	m_pFogDensityVariable->SetFloat(pRenderContext->GetFogInfo().FogDensity);
	m_pFogMaxHeightVariable->SetFloat(pRenderContext->GetFogInfo().FogMaxHeight);
	D3DXCOLOR fogcol = pRenderContext->GetFogInfo().FogColor;
	m_pFogColorVariable->SetRawValue(&fogcol, 0,sizeof(D3DXCOLOR));


	mfxLightVar->SetRawValue(&pRenderContext->GetLight(), 0, sizeof(Light));

	m_pWaterHeghtVariable->SetFloat(m_WaterHeight);
	// Set vertex buffer(s)
    UINT offset = 0;
	UINT vertexBufferStride = sizeof(VertexPosNormTex);
    m_pLevel->GetDevice()->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &vertexBufferStride, &offset );
   	
	// Set index buffer
	m_pLevel->GetDevice()->IASetIndexBuffer(m_pIndexBuffer,DXGI_FORMAT_R32_UINT,0);

    // Set primitive topology
    m_pLevel->GetDevice()->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

    D3D10_TECHNIQUE_DESC techDesc;
    m_pDefaultTechnique->GetDesc( &techDesc );
    for( UINT p = 0; p < techDesc.Passes; ++p )
    {
        m_pDefaultTechnique->GetPassByIndex(p)->Apply(0);
		m_pLevel->GetDevice()->DrawIndexed( m_VecIndices.size(), 0, 0 ); 
    }

	//Zorgt ervoor dat de resources die gebound zijn terug unbound zijn
	m_pShadowMapVariabele->SetResource(NULL);
	m_pDefaultTechnique->GetPassByIndex(0)->Apply(0);
}
void Terrain::DrawRefraction(const RenderContext* pRenderContext, D3DXPLANE refractionplane)
{
	m_Clippingplane = refractionplane;
	//m_bClipping = true;

	Draw(pRenderContext);
	//m_bClipping = false;
}
void Terrain::DrawReflection(const RenderContext* pRenderContext, D3DXMATRIX reflectionviewmatrix, D3DXPLANE reflectionplane)
{
	m_bReflection = true;
	m_bClipping = true;
	m_Clippingplane = reflectionplane;

	m_ReflectionViewMatrix = reflectionviewmatrix;
	ID3D10EffectTechnique* PreviousTechnique = m_pDefaultTechnique;

	m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByName("Reflection");
	if(!m_pDefaultTechnique->IsValid())MessageBox(0,_T("Technique not valid"),_T("ERROR"),0);

	Draw(pRenderContext);

	m_pDefaultTechnique = PreviousTechnique;
	m_bReflection = false;
	m_bClipping = false;
}
void Terrain::DrawShadowMap(const RenderContext* pRenderContext)
{
	ID3D10EffectTechnique* PreviousTechnique = m_pDefaultTechnique;

	m_LightWVPMatrix = pRenderContext->GetCamera()->GetWorldMatrix()*pRenderContext->GetCamera()->GetViewProj();

	m_pDefaultTechnique = m_pShadowTechnique;

	m_bShadowmap = true;
	Draw(pRenderContext);

	m_bShadowmap = false;
	m_pDefaultTechnique = PreviousTechnique;
}
void Terrain::CreateEffect(ContentManager *pContentManager)
{
	m_pDefaultEffect = pContentManager->GetEffect(m_pLevel->GetDevice(),  _T("./Effect/Terrain2.fx"));
	
	//get first technique found
	m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByIndex(0);
	if(!m_pDefaultTechnique->IsValid())MessageBox(0,_T("Technique not valid"),_T("ERROR"),0);

	m_pShadowTechnique = m_pDefaultEffect->GetTechniqueByName("Shadow");

	GetEffectVariables(m_pDefaultEffect);
}

void Terrain::GetEffectVariables(ID3D10Effect* pEffect)
{
	//get effect variables
	m_pWorldViewProjectionVariable = pEffect->GetVariableByName("gWVP")->AsMatrix();
	if(!m_pWorldViewProjectionVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WorldViewProjection Failed"),_T("ERROR"),0);

	m_pLightWVPVariable = pEffect->GetVariableByName("gLightWVP")->AsMatrix();
	//Texture Vars
	m_pTextureLowVariable = pEffect->GetVariableByName( "Texture1" )->AsShaderResource();
	if(!m_pTextureLowVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic TextureLow Failed"),_T("ERROR"),0);
	m_pTextureBaseVariabele = pEffect->GetVariableByName( "Texture2" )->AsShaderResource();
	if(!m_pTextureBaseVariabele->IsValid())MessageBox(0,_T("Getting EffectSemantic TextureBase Failed"),_T("ERROR"),0);
	m_pTextureMidVariabele = pEffect->GetVariableByName( "Texture3" )->AsShaderResource();
	if(!m_pTextureMidVariabele->IsValid())MessageBox(0,_T("Getting EffectSemantic TextureMid Failed"),_T("ERROR"),0);
	m_pTextureHighVariabele = pEffect->GetVariableByName( "Texture4" )->AsShaderResource();
	if(!m_pTextureHighVariabele->IsValid())MessageBox(0,_T("Getting EffectSemantic TextureHigh Failed"),_T("ERROR"),0);
	m_pBlendmapVariabele = pEffect->GetVariableByName( "Blendmap" )->AsShaderResource();
	if(!m_pBlendmapVariabele->IsValid())MessageBox(0,_T("Getting EffectSemantic Blendmap Failed"),_T("ERROR"),0);
	m_pShadowMapVariabele = pEffect->GetVariableByName( "gShadowMap" )->AsShaderResource();
	if(!m_pShadowMapVariabele->IsValid())MessageBox(0,_T("Getting EffectSemantic Blendmap Failed"),_T("ERROR"),0);


	m_pHeightOffsetVariable = pEffect->GetVariableByName("HeightOffset")->AsScalar();
	if(!m_pHeightOffsetVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic HeightOffset Failed"),_T("ERROR"),0);

	m_pWorldVariable = pEffect->GetVariableByName("gWorld")->AsMatrix();
	if(!m_pWorldVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WorldMatrix Failed"),_T("ERROR"),0);

	m_pEyePosVariable = pEffect->GetVariableByName("EyePos")->AsVector();

	mfxLightVar = pEffect->GetVariableByName("gLight");

	m_pWaterHeghtVariable = pEffect->GetVariableByName("WaterHeight")->AsScalar();

	clipPlanePtr = pEffect->GetVariableByName("ClipRefraction")->AsVector();

	m_pFogModeVariable = pEffect->GetVariableByName("g_fogMode")->AsScalar();
	m_pFogStartVariable = pEffect->GetVariableByName("g_fogStart")->AsScalar();
	m_pFogEndVariable = pEffect->GetVariableByName("g_fogEnd")->AsScalar();
	m_pFogDensityVariable = pEffect->GetVariableByName("g_fogDensity")->AsScalar();
	m_pFogMaxHeightVariable = pEffect->GetVariableByName("g_fogMaxHeight")->AsScalar();
	m_pFogColorVariable = pEffect->GetVariableByName("g_fogColor")->AsVector();
}

unsigned int Terrain::GetNumVertices()
{
	return m_NumColumns*m_NumRows;
}

unsigned int Terrain::GetNrOfTriangles()
{
	return 2 * (m_NumColumns-1) * (m_NumRows-1);
}

bool Terrain::LoadHeightMap(){
	
	//create already sized vector to store height values
	m_VecHeightValues.resize( GetNumVertices(), 0 );
	//open binary file 
	std::ifstream inFile;
	inFile.open(m_IntInfo.HeightmapFilename.c_str(),std::ios_base::binary);
	if ( !inFile )
	{
		MessageBox(0,L"Terrain file not found", _T("ERROR"),0);
		return false;
	}
	//read height info
	inFile.read((char*)&m_VecHeightValues[0], (std::streamsize)(GetNumVertices() * sizeof(unsigned short)) );	
	inFile.close();

	return true;
}

void Terrain::CreateVerticesAndTriangles()
{

	//Create DirectX10 Mesh 5.15
	int numQuadX = m_NumRows-1;
	int numQuadZ = m_NumColumns-1;
	double gridWidth = numQuadX * m_TileSize;
	double gridDepth = numQuadZ * m_TileSize;


	//create a grid, centered around origin
	//fill vertex vector
	m_VecVertices.reserve(GetNumVertices());

	for(unsigned int row=0;row<m_NumRows;row++)
	{
		for(unsigned int col=0;col<m_NumColumns;col++)
		{
			VertexPosNormTex v;
			v.pos.x = float( m_TileSize*col);
			v.pos.y = float(m_VecHeightValues[row*m_NumColumns+col]*m_ScaleHeight+m_Offset);
			v.pos.z = float( m_TileSize*row);
			v.tex.x = float(col)/m_NumColumns;
			v.tex.y = float(row)/m_NumRows;
			v.normal = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
			m_VecVertices.push_back(v);
		}
	}

	//create triangles
	unsigned int numTriangles = numQuadX * numQuadZ * 6;
	//resize vector for speed purposes
	m_VecIndices.reserve(numTriangles);
	m_Normallist.reserve(GetNumVertices());

	for(int i = 0; i < (int)GetNumVertices(); ++i)
	{
		//Zorgt ervoor dat de lijst niet leeg is
		vector<D3DXVECTOR3> temp;
		temp.push_back(D3DXVECTOR3(0 ,0 ,0));
		m_Normallist.push_back(temp);
	}

	for(unsigned int row = 0; row < (m_NumRows-1); ++row)
	{
		for(unsigned int column = 0 ; column < (m_NumColumns-1); ++column)
		{
			int index1 = row * m_NumColumns + column;
			int index2 = index1 + 1;

			int index3 = index1 + m_NumColumns;
			int index4 = index3 + 1;

			AddQuad(index1,index2, index3, index4);

			CalcNormal(index1, index3, index4);
			CalcNormal(index1, index4, index2);
		} 
	}
	//Al de normals smoothen(gemiddelde nemen) en toekennen
	for(int i = 0; i < (int)m_Normallist.size(); ++i)
	{
		//eerst het gemiddelde nemen
		D3DXVECTOR3 AverageNormal(0.0f, 0.0f, 0.0f);
		for(int j = 1; j < (int)m_Normallist[i].size(); ++j)
		{
			AverageNormal += m_Normallist[i][j];
		}
		AverageNormal /= (float)(m_Normallist[i].size()-1.0f);

		m_VecVertices[i].normal = AverageNormal;
	}
}
void Terrain::CalcNormal(unsigned int a, unsigned int b, unsigned int c)
{
	vector<VertexPosNormTex>::iterator vertex;

	VertexPosNormTex &p1 = m_VecVertices[a];

	VertexPosNormTex &p2 = m_VecVertices[b];

	VertexPosNormTex &p3 = m_VecVertices[c];

	D3DXVECTOR3 normal(0,1,0);
	D3DXVECTOR3 v1 = p2.pos - p1.pos;
	D3DXVECTOR3 v2 = p3.pos - p1.pos;

	D3DXVec3Cross(&normal, &v1, &v2);
	D3DXVec3Normalize(&normal,&normal);

	m_Normallist[a].push_back(normal);
	m_Normallist[b].push_back(normal);
	m_Normallist[c].push_back(normal);

}
void Terrain::AddTriangle (unsigned int a, unsigned int b, unsigned c)
{
	m_VecIndices.push_back(a);
	m_VecIndices.push_back(b);
	m_VecIndices.push_back(c);
}

void Terrain::AddQuad (unsigned int a, unsigned int b, unsigned c, unsigned d)
{
	AddTriangle(a,c,d);
	AddTriangle(a,d,b);
}
void Terrain::DefineInputlayout()
{
	// Define the input layout DO NOT USE D3D10_APPEND_ALIGNED_ELEMENT 
	D3D10_INPUT_ELEMENT_DESC layout[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		 { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 },
	};
	UINT numElements = sizeof(layout)/sizeof(layout[0]);

    // Create the input layout
    D3D10_PASS_DESC PassDesc;
	// Get the pass decriptor from the effect technique
    m_pDefaultTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    HR(m_pLevel->GetDevice()->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &m_pVertexLayout ));
}

void Terrain::BuildVertexBuffer()
{
	//fill a buffer description to copy the vertexdata into graphics memory
	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( VertexPosNormTex ) * m_VecVertices.size();
	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;

	D3D10_SUBRESOURCE_DATA initData;
	initData.pSysMem = m_VecVertices.data();
	//create a ID3D10Buffer in graphics memory containing the vertex info
	HR(m_pLevel->GetDevice()->CreateBuffer( &bd, &initData, &m_pVertexBuffer ));
}
void Terrain::BuildIndexBuffer()
{
	D3D10_BUFFER_DESC ibd;
    ibd.Usage = D3D10_USAGE_IMMUTABLE;
    ibd.ByteWidth = sizeof(DWORD) * m_VecIndices.size();
    ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    ibd.MiscFlags = 0;
    D3D10_SUBRESOURCE_DATA initData;
    initData.pSysMem = m_VecIndices.data();
    HR(m_pLevel->GetDevice()->CreateBuffer(&ibd, &initData, &m_pIndexBuffer));
}

void Terrain::CreatePhysicsTerrain()
{
	 NxHeightFieldDesc heightFieldDesc;    
	 heightFieldDesc.nbColumns           = m_NumColumns;    
	 heightFieldDesc.nbRows              = m_NumRows;    
	 heightFieldDesc.verticalExtent      = -10;    
	 heightFieldDesc.convexEdgeThreshold = 0;    
	 //Allocate storage for samples.    
	 heightFieldDesc.samples             = new NxU32[m_NumColumns*m_NumRows];    
	 heightFieldDesc.sampleStride        = sizeof(NxU32); 
	 
	 NxU8* currentByte = (NxU8*)heightFieldDesc.samples;    
	 for (NxU32 row = 0; row < m_NumRows; row++)
	 {        
		 for (NxU32 column = 0; column < m_NumColumns; column++)            
		 {            
			 NxHeightFieldSample* currentSample = (NxHeightFieldSample*)currentByte;
			 currentSample->height         = m_VecHeightValues[column*m_NumRows+row]/2; //from unsigned to signed, prevent clipping
			 //Desired height value. Signed 16 bit integer.           
			 currentSample->materialIndex0 = 0;            
			 currentSample->materialIndex1 = 0;            
			 currentSample->tessFlag = 0;            
			 currentByte += heightFieldDesc.sampleStride;
		 }        
	 }    
	 NxHeightField* heightField = m_pLevel->GetPhysicsScene()->getPhysicsSDK().createHeightField(heightFieldDesc);    

	
	 //Data has been copied therefore free the buffer.    
	 delete[] heightFieldDesc.samples;

	 NxHeightFieldShapeDesc heightFieldShapeDesc;   
	 heightFieldShapeDesc.heightField     = heightField;    
	 heightFieldShapeDesc.heightScale     = m_ScaleHeight*2;//undo division in currentSample->height  
	 heightFieldShapeDesc.rowScale        = m_TileSize;
	 heightFieldShapeDesc.columnScale     = m_TileSize;    
	 heightFieldShapeDesc.materialIndexHighBits = 0;    
	 heightFieldShapeDesc.holeMaterial = -1;
	 //heightFieldShapeDesc.
	 NxActorDesc actorDesc;    
	 actorDesc.shapes.pushBack(&heightFieldShapeDesc);    
	 actorDesc.globalPose.t = NxVec3(0,m_Offset,0);    
	 NxActor* newActor = m_pLevel->GetPhysicsScene()->createActor(actorDesc);

}
void Terrain::Smooth()
{
	std::vector<unsigned short> dest( m_VecHeightValues.size() );

	for(UINT i = 0; i < m_IntInfo.NumRows; ++i)
	{
		for(UINT j = 0; j < m_IntInfo.NumCols; ++j)
		{
			dest[i*m_IntInfo.NumCols+j] = (int)Average(i,j);
		}
	}

	// Replace the old heightmap with the filtered one.
	m_VecHeightValues = dest;
}
float Terrain::Average(UINT i, UINT j)
{
	// Function computes the average height of the ij element.
	// It averages itself with its eight neighbor pixels.  Note
	// that if a pixel is missing neighbor, we just don't include it
	// in the average--that is, edge pixels don't have a neighbor pixel.
	//
	// ----------
	// | 1| 2| 3|
	// ----------
	// |4 |ij| 6|
	// ----------
	// | 7| 8| 9|
	// ----------

	float avg = 0.0f;
	float num = 0.0f;

	for(UINT m = i-1; m <= i+1; ++m)
	{
		for(UINT n = j-1; n <= j+1; ++n)
		{
			if( InBounds(m,n) )
			{
				avg += m_VecHeightValues[m*m_IntInfo.NumCols + n];
				num += 1.0f;
			}
		}
	}

	return avg / num;
}
bool Terrain::InBounds(UINT i, UINT j)
{
	// True if ij are valid indices; false otherwise.
	return 
		i >= 0 && i < m_IntInfo.NumRows && 
		j >= 0 && j < m_IntInfo.NumCols;
}
void Terrain::GenerateBlendMap()
{
	//Eerst alle waardes tusse 0 & 1 brengen
	D3DXCOLOR* Heightvalues = new D3DXCOLOR[m_VecHeightValues.size()];

	for(int pos = 0; pos < (int)m_VecHeightValues.size(); ++pos)
	{
		//65535 is not a magic number its the max size of an int
		//To make the values between 0 and 1
		float Heightvalue = (float)m_VecHeightValues[pos]/65535.0f;
		D3DXVECTOR3 currentnormal = m_VecVertices[pos].normal;

		D3DXCOLOR temp;

		if(Heightvalue > 0.7f)
			tstring test;
		//Hier word de blendmap gemaakt
		//Sand level
		float snow = 0.0f;
		float rock = 0.0f;
		float grass = 0.0f;
		float sand = 0.0f;

		if(Heightvalue > m_SnowLine)
		{
			//percentage sneeuw
			snow = 1.0f * ((Heightvalue - m_SnowLine) / (1.0f - m_SnowLine));
			rock = 1.0f - snow;
		} else if(Heightvalue > m_RockLine)
		{
			rock = 1.0f * ((Heightvalue - m_RockLine) / (m_SnowLine - m_RockLine));
			grass = 1.0f - rock;
		} else if(Heightvalue > m_GrassLine)
		{
			grass = 1.0f * ((Heightvalue - m_GrassLine) / (m_RockLine - m_GrassLine)) + 0.4f;
			sand = 1.0f - grass - 0.4f;
		} else
		{
			sand = 1.0f;
		}
		//Hoe stijler hoe meer rots er tezien is
		float stijlheid;
		stijlheid = abs(D3DXVec3Dot(&D3DXVECTOR3(0.0f, 0.0f, 1.0f), &currentnormal));
		stijlheid += abs(D3DXVec3Dot(&D3DXVECTOR3(1.0f, 0.0f, 0.0f), &currentnormal));
		
		if(stijlheid < 0.2f)
			stijlheid = 0.0f;

		temp.r = sand - 0.5f*stijlheid;
		temp.g = grass -0.5f*stijlheid;
		temp.b = rock + 0.7f*stijlheid;
		temp.a = snow;

		Heightvalues[pos] = temp;
	}

	/////////////////
	//Creating the texture
	////////////////	
	ID3D10Texture2D *tex2;
    D3D10_TEXTURE2D_DESC tdesc2;
    D3D10_SUBRESOURCE_DATA tbsd2;

    tbsd2.pSysMem = (void *)(Heightvalues);
    tbsd2.SysMemPitch = m_NumColumns*16;
    tbsd2.SysMemSlicePitch = m_NumRows*m_NumColumns*16; // Not needed since this is a 2d texture

    tdesc2.Width = m_NumColumns;
    tdesc2.Height = m_NumRows;
    tdesc2.MipLevels = 1;
    tdesc2.ArraySize = 1;

    tdesc2.SampleDesc.Count = 1;
    tdesc2.SampleDesc.Quality = 0;
    tdesc2.Usage = D3D10_USAGE_DEFAULT;
    tdesc2.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
    tdesc2.BindFlags = D3D10_BIND_SHADER_RESOURCE;

    tdesc2.CPUAccessFlags = 0;
    tdesc2.MiscFlags = 0;

    m_pLevel->GetDevice()->CreateTexture2D(&tdesc2,&tbsd2,&tex2);

	D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc2;

    D3D10_TEXTURE2D_DESC desc2;
    m_pBlendMapVar = tex2;
    m_pBlendMapVar->GetDesc( &desc2 );
		
    srvDesc2.Format = desc2.Format;
    srvDesc2.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
    srvDesc2.Texture2D.MipLevels = desc2.MipLevels;
    srvDesc2.Texture2D.MostDetailedMip = desc2.MipLevels -1;

	m_pBlendMap = NULL;
	m_pLevel->GetDevice()->CreateShaderResourceView( m_pBlendMapVar, &srvDesc2, &m_pBlendMap );

}